home *** CD-ROM | disk | FTP | other *** search
- ######################################################################
- # #
- # Use at your own risk. This is just a quick-and-dirty RPN stack #
- # calculator, works on both decimal (signed and unsigned), hex #
- # integers, and floating point. I put it #
- # together for my own use, not yours, but feel free to use it as #
- # long as you don't complain about what it doesn't do. #
- # Improvements, of course, are welcome. #
- # #
- # Operations: Top of stack is 'y', next is 'x'. #
- # ~ bitwise NOT #
- # +,-,*,/,|,&,% Does x OP y. #
- # ^ x eor y or #
- # x^y in floating point mode #
- # < x << y #
- # > x >> y #
- # - <z> insert - sign #
- # n change y's sign #
- # q dup y #
- # i swap x and y #
- # m switch decimal/hex modes #
- # x show current mode #
- # h,? help #
- # <backspace> pop stack #
- # <space> enter number #
- # #
- # Floating point extensions #
- # #
- # f <o> floor(y) #
- # f <so> ceil(y) #
- # #
- # f <oz> fmod(x,y) #
- # h <oz> hypot(x,y) #
- # p <oz> x**y #
- # s <oz> sqrt(y) #
- # #
- # l <z> log(y) #
- # l <sz> exp(y) #
- # l <oz> log10(y) #
- # #
- # c <o> cos(y) #
- # s <o> sin(y) #
- # t <o> tan(y) #
- # #
- # c <so> acos(y) #
- # s <so> asin(y) #
- # t <so> atan(y) #
- # #
- # c <z> cosh(y) #
- # s <z> sinh(y) #
- # t <z> tanh(y) #
- # #
- # c <sz> acosh(y) #
- # s <sz> asinh(y) #
- # t <sz> atanh(y) #
- # #
- # t <oz> atan2(x,y) #
- # #
- # The mode indicator indicates whether hex or dec is active. #
- # All calculations performed in signed decimal. #
- # #
- ######################################################################
-
- alpha::mode Calc 0.1.6 Calc::dummy {} {calcMenu} {
- # Alpha will shift this in and out of global scope as necessary
- newPref variable tcl_precision 17 Calc
- # Set display precision in Calc mode.
- newPref variable displayPrec 6 Calc
-
- addMenu calcMenu "Calc" Calc
- } help {file "Calculator Help"}
-
- proc Calc::dummy {} {}
-
- proc calcMenu {} {}
-
- # Vince moved this here to avoid having calc.tcl sourced
- # at every startup. It works fine here anyway.
- hook::register keyboard calcSwitchKeyboard
-
- proc calculator {} {
- global tileLeft tileTop calcMode
- if {[set ind [lsearch -exact [winNames] {* Calc *}]] >= 0} {
- bringToFront {* Calc *}
- return
- }
- set calcMode 3
- calcbind 1
- new -g $tileLeft $tileTop 200 300 -n {* Calc *} -m Calc -shell 1
- calcMenuEnable $calcMode
- }
-
- ascii 0x2b "binop +" Calc
- ascii 0x2d "binop -" Calc
- ascii 0x2a "binop *" Calc
- ascii 0x2f "binop /" Calc
- ascii 0x5e "binop ^" Calc
- ascii 0x26 "binop &" Calc
- ascii 0x25 "binop %" Calc
- ascii 0x3e "binop >>" Calc
- ascii 0x3c "binop <<" Calc
- ascii 0x7c "binop |" Calc
- ascii 0x3f {edit -r -c [file join $HOME Help {Calculator Help}]} Calc
- ascii 0x68 {edit -r -c [file join $HOME Help {Calculator Help}]} Calc
- ascii 0x71 calcDup Calc
- ascii 0x69 calcEx Calc
- ascii 0x6d changeCalcMode Calc
- ascii 0x78 "calcShow" Calc
- ascii 0x20 calcEnter Calc
- ascii 0x08 calcDel Calc
- ascii 0x25 "function %" Calc
- ascii 0x5e "function ^" Calc
- ascii 0x6e "unaryop -" Calc
- ascii 0x7e "unaryop ~" Calc
-
- #=============================================================================
- #
- # Calculator Menu:
- #
- #=============================================================================
- Menu -n Calc -p calcMenuProc -M Calc {
- "!qduplicateY"
- "!iswapXY"
- "!mchangeMode"
- "!xshowMode"
- "(-"
- "!nnegate"
- "/-<BinsertMinus"
- "!%mod"
- "(-"
- {Menu -n Boolean -p CalcBooleanItem -M Calc {
- "!&and"
- "!|or"
- "!^xor"
- "(-"
- "!<shiftLeft"
- "!>shiftRight"
- "!~not"
- }}
- {Menu -n ExpAndLog -p CalcMenuItem -M Calc {
- "/L<B<Uexp"
- "/L<Blog"
- "/L<B<Ilog10"
- }}
- {Menu -n Trigonometric -p CalcMenuItem -M Calc {
- "/C<Icos"
- "/S<Isin"
- "/T<Itan"
- "(-"
- "/C<I<Uacos"
- "/S<I<Uasin"
- "/T<I<Uatan"
- }}
- {Menu -n Hyperbolic -p CalcMenuItem -M Calc {
- "/C<Bcosh"
- "/S<Bsinh"
- "/T<Btanh"
- "(-"
- "/C<B<Uach"
- "/S<B<Uash"
- "/T<B<Uath"
- }}
- {Menu -n OtherMathFunctions -p calcMenuProc -M Calc {
- "/F<Ifloor"
- "/F<I<Uceil"
- "(-"
- "/T<B<Iatan2"
- "/F<B<I!%fmod"
- "/H<B<Ihypot"
- "/P<B<I!^pow"
- "/S<B<Isqrt"
- }}
- {Menu -n Constants -p calcMenuProc -M Calc {
- "/E<I<Ue"
- "/P<Ipi"
- }}
- "(-"
- "!?calculatorHelp"
- }
-
- Bind '-' <z> { typeText "-" } Calc
-
- Bind 'f' <o> "unaryop floor" Calc
- Bind 'f' <os> "unaryop ceil" Calc
- Bind 'f' <oz> "function fmod" Calc
- Bind 'h' <oz> "function hypot" Calc
- Bind 'p' <oz> "function pow" Calc
- Bind 's' <oz> "unaryop sqrt" Calc
-
- Bind 'l' <z> "unaryop log" Calc
- Bind 'l' <sz> "unaryop exp" Calc
- Bind 'l' <oz> "unaryop log10" Calc
-
- Bind 'c' <o> "unaryop cos" Calc
- Bind 's' <o> "unaryop sin" Calc
- Bind 't' <o> "unaryop tan" Calc
- Bind 'c' <os> "unaryop acos" Calc
- Bind 's' <os> "unaryop asin" Calc
- Bind 't' <os> "unaryop atan" Calc
- Bind 'c' <z> "unaryop cosh" Calc
- Bind 's' <z> "unaryop sinh" Calc
- Bind 't' <z> "unaryop tanh" Calc
- Bind 'c' <sz> "unaryop ach" Calc
- Bind 's' <sz> "unaryop ash" Calc
- Bind 't' <sz> "unaryop ath" Calc
- Bind 't' <oz> "function atan2" Calc
-
- Bind 'p' <o> "insertText {3.14159265358979323}" Calc
- Bind 'e' <so> "insertText {2.718281828459045}" Calc
-
- proc CalcMenuItem {menu item} {
- unaryop $item
- }
-
- proc calcMenuProc {menu item} {
- switch $item {
- duplicateY {
- calcDup
- }
- swapXY {
- calcEx
- }
- changeMode {
- changeCalcMode
- }
- showMode {
- calcShow
- }
- negate {
- unaryop -
- }
- insertMinus {
- typeText "-"
- }
- mod {
- function "%"
- }
- sqrt {
- unaryop sqrt
- }
- floor {
- unaryop floor
- }
- ceil {
- unaryop ceil
- }
- e {
- insertText {2.718281828459045}
- }
- pi {
- insertText {3.14159265358979323}
- }
- calculatorHelp {
- global HOME
- edit -r -c [file join $HOME Help {Calculator Help}]
- }
- default {
- function $item
- }
- }
- }
-
- proc CalcBooleanItem {menu item} {
- switch $item {
- and {
- binop &
- }
- or {
- binop |
- }
- xor {
- binop ^
- }
- shiftLeft {
- binop <<
- }
- shiftRight {
- binop >>
- }
- not {
- unaryop ~
- }
- }
- }
-
- proc calcMenuEnable {arg} {
- if {$arg == 3} {
- set a "on"
- set b "off"
- } else {
- set a "off"
- set b "on"
- }
- enableMenuItem Calc Boolean $b
- enableMenuItem Calc ExpAndLog $a
- enableMenuItem Calc Trigonometric $a
- enableMenuItem Calc Hyperbolic $a
- enableMenuItem Calc OtherMathFunctions $a
- enableMenuItem Calc Constants $a
- }
-
- proc calcbind {flag {keys ""}} {
- global keyboard
- if {$flag == 0} {
- set func "unbind"
- } else {
- set func "Bind"
- }
- if {$keys == ""} {
- set keys $keyboard
- }
- switch -- $keys {
- "Canadian - CSA" -
- "Canadian - ISO" {set key "'-' <o> "}
- "Croatian" {
- set key "'<' <so> "
- set pro "{unaryop ~}"
- catch "$func $key $pro Calc"
- set key "'i' <o> "
- set pro "{function ^}"
- catch "$func $key $pro Calc"
- set key "'ç' <o> "
- catch "$func $key $pro Calc"
- set key "0x2a <so> "
- }
- "Danish" {set key "'i' <o> "}
- "Español - ISO" {set key "'1' <o> "}
- "Finnish" -
- "German" -
- "Norwegian" -
- "Spanish" -
- "Swedish" -
- "Swiss French" -
- "Swiss German" {set key "'7' <o> "}
- "Flemish" -
- "French" -
- "French - numerical" {set key "'l' <so> "}
- "Italian" {set key "':' <o> "}
- "Slovenian" {
- set key "0x27 <o> "
- set pro "{function ^}"
- catch "$func $key $pro Calc"
- set key "'æ' <so> "
- }
- default {return}
- }
- set pro "{binop |}"
- catch "$func $key $pro Calc"
- }
-
- proc calcSwitchKeyboard {} {
- global oldkeyboard keyboard
- calcbind 0 $oldkeyboard
- calcbind 1
- }
-
- proc changeCalcMode {} {
- global calcMode
-
- goto [maxPos]
- if {[pos::compare [getPos] > [minPos]]} {
- if {[lookAt [pos::math [getPos] - 1]] != "\r"} calcEnter
- set nums {}
- set t ""
- foreach n [split [getText [minPos] [pos::math [maxPos] - 1]] "\r"] {
- lappend nums [calcGet $n]
- }
- set calcMode [expr {($calcMode + 1) % 4}]
- foreach n $nums {
- append t "[calcPut $n]\r"
- }
- replaceText [minPos] [maxPos] $t
- } else {
- set calcMode [expr {($calcMode + 1) % 4}]
- }
- calcShow
- calcMenuEnable $calcMode
- }
-
-
- proc calcShow {} {
- global calcMode
- switch -- "$calcMode" {
- 0 {message "Signed decimal" }
- 1 {message "Unsigned decimal"}
- 2 {message "Unsigned hexadecimal"}
- 3 {message "Floating Point"}
- }
- }
-
-
- proc calcGet {in} {
- global calcMode
-
- switch -- "$calcMode" {
- 0 {scan $in "%d" num; return $num}
- 1 {scan $in "%u" num; return $num}
- 2 {scan $in "%x" num; return $num}
- 3 {scan $in "%g" num; return $num}
- }
- error "Bad hex num '$in'"
- }
-
- proc calcPut {in} {
- global CalcmodeVars calcMode
- set prec $CalcmodeVars(displayPrec)
-
- if {$prec < 0} {
- set prec 0
- set CalcmodeVars(displayPrec) $prec
- }
- if {$prec > 17} {
- set prec 17
- set CalcmodeVars(displayPrec) $prec
- }
-
- if {$calcMode != 3} {
- regexp {[0-9-]+} $in in
- }
- switch -- $calcMode {
- 0 {return [format "%25d" $in]}
- 1 {return [format "%25u" $in]}
- 2 {return [format "%25x" $in]}
- 3 {return [format "%25.${prec}g" $in]}
- }
- }
-
- proc binop {op} {
- global calcMode
- if {$calcMode == 3 && ($op == "&" || $op == "|" \
- || $op == "<<" || $op == ">>")} {
- beep
- message "${op} does not work in floating point mode"
- return
- }
- goto [maxPos]
- if {[lookAt [pos::math [getPos] - 1]] != "\r"} calcEnter
- set pos [lineStart [getPos]]
- set st_y [lineStart [pos::math $pos - 1]]
- set st_x [lineStart [pos::math $st_y - 1]]
- if {[pos::compare $st_y == $st_x]} { beep; return}
- set res [eval expr {[calcGet [getText $st_x $st_y]] $op \
- [calcGet [getText $st_y $pos]]}]
- replaceText $st_x [maxPos] [calcPut $res] "\r"
- }
-
- proc unaryop {op} {
- global calcMode
- if {$calcMode != 3 && $op != "-" && $op != "~"} {
- beep
- message "${op} works only in floating point mode"
- return
- } elseif {$calcMode == 3 && $op == "~"} {
- beep
- message "${op} does not work in floating point mode"
- return
- }
- goto [maxPos]
-
- set pos [getPos]
- set last [lineStart [pos::math [getPos] - 1]]
- set yvar [calcGet [getText $last $pos]]
- switch -- $op {
- "ach" {set res [eval expr "log($yvar+sqrt($yvar*$yvar-1))"]}
- "ash" {set res [eval expr "log($yvar+sqrt($yvar*$yvar+1))"]}
- "ath" {set res [eval expr "0.5*log((1+$yvar)/(1-$yvar))"]}
- default {set res [eval expr "${op}($yvar)"]}
- }
- replaceText $last $pos [calcPut $res] "\r"
- }
-
- proc function {op} {
- global calcMode
- if {$calcMode != 3} {
- if { $op == "^" || $op == "%"} {
- binop $op
- return
- }
- beep
- message "${op} works only in floating point mode"
- return
- }
- if { $op == "^" } {set op "pow"}
- if { $op == "%" } {set op "fmod"}
- goto [maxPos]
- if {[lookAt [pos::math [getPos] - 1]] != "\r"} calcEnter
- set pos [lineStart [getPos]]
- set st_y [lineStart [pos::math $pos - 1]]
- set st_x [lineStart [pos::math $st_y - 1]]
- if {[pos::compare $st_y == $st_x]} { beep; return}
- set res [eval expr "${op}([calcGet [getText $st_x $st_y]],\
- [calcGet [getText $st_y $pos]])"]
- replaceText $st_x [maxPos] "[calcPut $res]\r"
- }
-
- proc calcEx {} {
- goto [maxPos]
- if {[lookAt [pos::math [getPos] - 1]] != "\r"} calcEnter
- set pos [lineStart [getPos]]
- set st_y [lineStart [pos::math $pos - 1]]
- set st_x [lineStart [pos::math $st_y - 1]]
- if {[pos::compare $st_y == $st_x]} { beep; return}
- replaceText $st_x [maxPos] "[getText $st_y $pos][getText $st_x $st_y]"
- }
-
-
- proc calcEnter {} {
- global calcMode
- goto [maxPos]
- switch -- "$calcMode" {
- 0 {set ex {[0-9-]+$}}
- 1 {set ex {[0-9]+$}}
- 2 {set ex {[0-9a-f]+$}}
- 3 {set ex {[eE0-9.-]+$}}
- }
- if {[regexp -- $ex [getText [lineStart [getPos]] [getPos]] num]} {
- set num [calcGet $num]
- replaceText [lineStart [getPos]] [getPos] [calcPut $num] "\r"
- } else {
- beep
- beginningOfLine
- killLine
- }
- }
-
- proc calcDel {} {
- goto [maxPos]
- if {[is::Eol [lookAt [pos::math [getPos] - 1]]]} {
- deleteText [lineStart [pos::math [getPos] - 1]] [getPos]
- } else {
- backSpace
- }
- }
-
- proc calcDup {} {
- goto [maxPos]
- if {![is::Eol [lookAt [pos::math [getPos] - 1]]]} calcEnter
- set to [lineStart [getPos]]
- set from [lineStart [pos::math $to - 1]]
- set t [getText $from $to]
- insertText $t
- }
-
-